using Microsoft.Extensions.Logging;
using SumerCoreDevOps.Infrastructure.Tcp;
using SumerCoreDevOps.Shared.Enums;
using SumerCoreDevOps.Shared.Models.Messages;
using System.Runtime.InteropServices;

namespace SumerCoreDevOps.ExecuteNodeApi.Services;

/// <summary>
/// 热注册服务 - 支持运行时动态注册到新的主节点
/// </summary>
public class HotRegistrationService
{
    private readonly ILogger<HotRegistrationService> _logger;
    private readonly TcpMultiMasterClient _tcpClient;
    private readonly MasterDiscoveryService _discoveryService;
    private readonly NodeConfigPersistenceService _persistenceService;
    private readonly HeartbeatService _heartbeatService;
    private readonly SemaphoreSlim _registrationLock = new(1, 1);

    // 重试配置
    private const int MaxRetries = 5;
    private static readonly TimeSpan[] RetryDelays = new[]
    {
        TimeSpan.FromSeconds(1),
        TimeSpan.FromSeconds(2),
        TimeSpan.FromSeconds(4),
        TimeSpan.FromSeconds(8),
        TimeSpan.FromSeconds(16)
    };

    // 注册结果
    private TaskCompletionSource<HotRegistrationResult>? _registrationTcs;
    private string? _generatedNodeKey;
    private string? _requestedNodeName;

    public HotRegistrationService(
        ILogger<HotRegistrationService> logger,
        TcpMultiMasterClient tcpClient,
        MasterDiscoveryService discoveryService,
        NodeConfigPersistenceService persistenceService,
        HeartbeatService heartbeatService)
    {
        _logger = logger;
        _tcpClient = tcpClient;
        _discoveryService = discoveryService;
        _persistenceService = persistenceService;
        _heartbeatService = heartbeatService;
    }

    /// <summary>
    /// 执行热注册
    /// </summary>
    public async Task<HotRegistrationResult> HotRegisterAsync(
        string discoveryUrl,
        string? joinToken = null,
        string? nodeName = null,
        CancellationToken cancellationToken = default)
    {
        // 确保同一时间只有一个注册操作
        if (!await _registrationLock.WaitAsync(0, cancellationToken))
        {
            return HotRegistrationResult.CreateFailure("另一个注册操作正在进行中,请稍后再试");
        }

        NodeConfig? backupConfig = null;

        try
        {
            _logger.LogInformation("开始热注册: DiscoveryUrl={DiscoveryUrl}, JoinToken={HasToken}, NodeName={NodeName}",
                discoveryUrl, !string.IsNullOrEmpty(joinToken), nodeName ?? "(自动检测)");

            // 1. 备份当前配置
            backupConfig = await _persistenceService.LoadConfigAsync();
            if (backupConfig != null)
            {
                _logger.LogInformation("已备份当前节点配置: NodeId={NodeId}, NodeName={NodeName}",
                    backupConfig.NodeId, backupConfig.NodeName);
            }

            // 2. 发现主节点
            List<MasterEndpointInfo> masters;
            try
            {
                _logger.LogInformation("正在发现主节点...");
                masters = await _discoveryService.DiscoverMastersAsync(discoveryUrl);

                if (masters.Count == 0)
                {
                    throw new InvalidOperationException("未发现任何可用的主节点");
                }

                _logger.LogInformation("成功发现 {Count} 个主节点", masters.Count);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "发现主节点失败");
                return HotRegistrationResult.CreateFailure($"无法连接到主节点: {ex.Message}");
            }

            // 3. 转换为 MasterEndpoint 格式
            var endpoints = masters.Select(m => new MasterEndpoint
            {
                Host = m.Host,
                Port = m.TcpPort,
                Priority = m.Priority
            }).ToList();

            // 4. 带重试的注册流程
            Exception? lastException = null;
            for (int attempt = 0; attempt < MaxRetries; attempt++)
            {
                try
                {
                    if (attempt > 0)
                    {
                        var delay = RetryDelays[Math.Min(attempt - 1, RetryDelays.Length - 1)];
                        _logger.LogInformation("第 {Attempt}/{MaxRetries} 次重试,等待 {Delay} 秒...",
                            attempt + 1, MaxRetries, delay.TotalSeconds);
                        await Task.Delay(delay, cancellationToken);
                    }

                    _logger.LogInformation("尝试连接到主节点 (第 {Attempt}/{MaxRetries} 次)...",
                        attempt + 1, MaxRetries);

                    // 重新连接到新的主节点
                    await _tcpClient.ReconnectAsync(endpoints, cancellationToken);

                    if (!_tcpClient.IsConnected())
                    {
                        throw new InvalidOperationException("TCP连接建立失败");
                    }

                    _logger.LogInformation("TCP连接已建立,开始注册...");

                    // 监听注册响应
                    _tcpClient.OnMessageReceived += HandleRegistrationMessageAsync;
                    _registrationTcs = new TaskCompletionSource<HotRegistrationResult>();

                    // 发送注册消息
                    _generatedNodeKey = Guid.NewGuid().ToString();
                    _requestedNodeName = nodeName ?? Environment.MachineName;
                    var registerMessage = new NodeRegisterMessage
                    {
                        JoinToken = joinToken,
                        NodeKey = _generatedNodeKey,
                        NodeName = _requestedNodeName,
                        SupportedEnvironments = new List<string>(),
                        HardwareInfo = new NodeHardwareInfo
                        {
                            CpuCores = Environment.ProcessorCount,
                            TotalMemoryMB = GC.GetGCMemoryInfo().TotalAvailableMemoryBytes / 1024 / 1024,
                            OperatingSystem = Environment.OSVersion.ToString(),
                            Architecture = RuntimeInformation.ProcessArchitecture.ToString()
                        }
                    };

                    await _tcpClient.SendToAllAsync(TcpMessageType.NodeRegister, registerMessage);
                    _logger.LogInformation("已发送注册请求,等待响应...");

                    // 等待注册响应 (超时30秒)
                    using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
                    using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);

                    try
                    {
                        var result = await _registrationTcs.Task.WaitAsync(linkedCts.Token);

                        if (result.Success)
                        {
                            _logger.LogInformation("注册成功!");

                            // 删除备份配置 (完全替换)
                            if (backupConfig != null)
                            {
                                _logger.LogInformation("删除旧配置,应用新配置");
                            }

                            return result;
                        }
                        else
                        {
                            throw new InvalidOperationException($"注册被拒绝: {result.ErrorMessage}");
                        }
                    }
                    catch (OperationCanceledException) when (timeoutCts.IsCancellationRequested)
                    {
                        throw new TimeoutException("等待注册响应超时");
                    }
                }
                catch (Exception ex)
                {
                    lastException = ex;
                    _logger.LogWarning(ex, "注册尝试失败 (第 {Attempt}/{MaxRetries} 次): {Message}",
                        attempt + 1, MaxRetries, ex.Message);

                    // 清理
                    _tcpClient.OnMessageReceived -= HandleRegistrationMessageAsync;
                    _registrationTcs = null;
                }
            }

            // 所有重试都失败了
            _logger.LogError("热注册失败,已重试 {MaxRetries} 次", MaxRetries);

            // 回滚到旧配置
            if (backupConfig != null)
            {
                _logger.LogInformation("正在回滚到旧配置...");
                try
                {
                    await _persistenceService.SaveConfigAsync(backupConfig);

                    // 尝试重连到旧主节点
                    var oldEndpoints = new List<MasterEndpoint>
                    {
                        new MasterEndpoint
                        {
                            Host = backupConfig.ServerHost,
                            Port = backupConfig.ServerPort,
                            Priority = 1
                        }
                    };

                    await _tcpClient.ReconnectAsync(oldEndpoints, cancellationToken);
                    _logger.LogInformation("已回滚到旧配置并重新连接");

                    return HotRegistrationResult.CreateFailure(
                        $"注册失败 (已重试{MaxRetries}次): {lastException?.Message ?? "未知错误"}。已回滚到原配置。");
                }
                catch (Exception rollbackEx)
                {
                    _logger.LogError(rollbackEx, "回滚配置失败");
                    return HotRegistrationResult.CreateFailure(
                        $"注册失败且回滚失败: {lastException?.Message ?? "未知错误"}。建议重启服务。");
                }
            }

            return HotRegistrationResult.CreateFailure(
                $"注册失败 (已重试{MaxRetries}次): {lastException?.Message ?? "未知错误"}");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "热注册过程中发生严重错误");
            return HotRegistrationResult.CreateFailure($"热注册失败: {ex.Message}");
        }
        finally
        {
            _registrationLock.Release();
            _tcpClient.OnMessageReceived -= HandleRegistrationMessageAsync;
            _registrationTcs = null;
        }
    }

    /// <summary>
    /// 处理注册响应消息
    /// </summary>
    private async Task HandleRegistrationMessageAsync(string masterId, TcpMessageType messageType, object body)
    {
        if (messageType == TcpMessageType.RegisterResponse && body is RegisterResponseMessage response)
        {
            _logger.LogInformation("收到注册响应: Success={Success}, NodeId={NodeId}",
                response.Success, response.NodeId);

            if (_registrationTcs == null || _registrationTcs.Task.IsCompleted)
            {
                return;
            }

            if (response.Success)
            {
                // 保存新配置
                var config = new NodeConfig
                {
                    NodeId = response.NodeId,
                    NodeKey = _generatedNodeKey!,
                    NodeName = _requestedNodeName ?? Environment.MachineName,
                    ConnectionToken = response.ConnectionToken ?? string.Empty,
                    ServerHost = masterId.Split(':')[0],
                    ServerPort = int.Parse(masterId.Split(':')[1]),
                    SavedAt = DateTime.UtcNow
                };

                try
                {
                    await _persistenceService.SaveConfigAsync(config);
                    _logger.LogInformation("新节点配置已保存: NodeId={NodeId}", config.NodeId);

                    // 重启心跳服务,立即向新主节点发送心跳
                    _logger.LogInformation("重启心跳服务...");
                    _heartbeatService.Restart();

                    _registrationTcs.TrySetResult(HotRegistrationResult.CreateSuccess(
                        response.NodeId,
                        config.NodeName,
                        masterId));
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "保存配置失败");
                    _registrationTcs.TrySetResult(HotRegistrationResult.CreateFailure($"保存配置失败: {ex.Message}"));
                }
            }
            else
            {
                _registrationTcs.TrySetResult(HotRegistrationResult.CreateFailure(
                    response.ErrorMessage ?? "注册被拒绝"));
            }
        }

        await Task.CompletedTask;
    }
}

/// <summary>
/// 热注册结果
/// </summary>
public class HotRegistrationResult
{
    public bool Success { get; set; }
    public long NodeId { get; set; }
    public string NodeName { get; set; } = string.Empty;
    public string MasterId { get; set; } = string.Empty;
    public string ErrorMessage { get; set; } = string.Empty;

    public static HotRegistrationResult CreateSuccess(long nodeId, string nodeName, string masterId)
    {
        return new HotRegistrationResult
        {
            Success = true,
            NodeId = nodeId,
            NodeName = nodeName,
            MasterId = masterId
        };
    }

    public static HotRegistrationResult CreateFailure(string errorMessage)
    {
        return new HotRegistrationResult
        {
            Success = false,
            ErrorMessage = errorMessage
        };
    }
}
